package se.webbzon.boltzmann.battle.object.status;

import java.util.Collection;
import java.util.List;

import se.webbzon.boltzmann.battle.object.npc.BattleNPC;
import se.webbzon.boltzmann.battle.property.BattleBuff;
import se.webbzon.boltzmann.battle.property.BattleProperty;
import se.webbzon.boltzmann.battle.property.BattlePropertyListener;
import se.webbzon.boltzmann.battle.strategy.AbstractStrategy;
import se.webbzon.boltzmann.effect.Effect;
import se.webbzon.boltzmann.effect.HealthLossEffect;
import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldobject.WorldObject;
import se.webbzon.oschi01.worldobject.WorldStaticGroup;
import se.webbzon.oschi01.worldobject.WorldStaticObject;
import se.webbzon.oschi01.worldobject.appearance.NoAppearance3D;

public class BattleStatusGroup extends WorldStaticGroup implements BattlePropertyListener {
	
	// The default time for refreshing buffs
	private static final int buffRefreshTime = 30;
	
	// The world area associated with this battle status group
	private final WorldArea world;
	
	// The non-player battle character associated with this status group
	private final BattleNPC npc;
	
	// The status bar associated with this status group
	private final BattleStatusBar statusBar;
	
	// The old health and energy
	private int oldHealth, oldEnergy;
	
	// A timer used to refresh the index of all buffs
	private int buffRefreshTimer;
	
	/*============================================================
	Constructors
	============================================================*/
	
	/** Creates a new non-player battle character status. **/
	public BattleStatusGroup(WorldArea world, BattleNPC npc) {
		super(WorldObject.onStep + WorldObject.onDestroy,0,new NoAppearance3D());
		this.world = world;
		this.npc = npc;
		
		final BattleProperty property = npc.getProperty();
		List<BattleBuff> buffs = property.getBuffs();
		for (int index = 0; index < buffs.size(); index ++) {
			BattleStatusBuff statusBuff = new BattleStatusBuff(index,buffs.get(index));
			addInstance(statusBuff);
			world.createInstance(statusBuff);
		}
		npc.getProperty().addListener(this);
		oldHealth = property.getHealth();
		oldEnergy = property.getEnergy();
		
		statusBar = new BattleStatusBar(property);
		addInstance(statusBar);
		world.createInstance(statusBar);
		
		buffRefreshTimer = -1;
		
		setSize(npc.getHeight()/2,npc.getWidth()/2,1);
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Returns the non-player battle character associated with this status. **/
	public BattleNPC getNPC() {
		return npc;
	}
	
	@Override public void onStep(WorldArea world) {
		setPosition(npc.getX(),npc.getY()-npc.getHeight()/4,npc.getZ());
		final BattleProperty property = npc.getProperty();
		if(property.getHealth() != oldHealth || property.getEnergy() != oldEnergy) {
		
			if (property.getHealth() < oldHealth)
				oldHealth--;
			else if (property.getHealth() > oldHealth)
				oldHealth++;
			
			if (property.getEnergy() < oldEnergy)
				oldEnergy--;
			else if (property.getHealth() > oldEnergy)
				oldEnergy++;
			
			statusBar.setStatus(oldHealth,oldEnergy,
								property.getMaxHealth(),property.getMaxEnergy());
		}
		
		if (buffRefreshTimer >= 0) {
			if (buffRefreshTimer == 0)
				refreshBuffs();
			buffRefreshTimer--;
		} 
	}
	
	@Override public void onDestroy(WorldArea world) {
		for (WorldStaticObject instance : getInstances())
			world.destroyInstance(instance);
	}
	
	@Override public void onSetMaxHealth(BattleProperty property, int maxHealth) {
		statusBar.setStatus(property.getHealth(),property.getEnergy(),
							maxHealth,property.getMaxEnergy());
	}

	@Override public void onSetHealth(BattleProperty property, int health) {
		final int damage = oldHealth - health;
		BattleStatusDamage statusDamage = new BattleStatusDamage(damage);
		addInstance(statusDamage);
		world.createInstance(statusDamage);
		for (int i = 0; i < damage; i++) {
			Effect effect = new HealthLossEffect(npc);
			effect.launch(world);
		}
	}

	@Override public void onSetMaxEnergy(BattleProperty property, int maxEnergy) {
		statusBar.setStatus(property.getHealth(),property.getEnergy(),
							property.getMaxHealth(),maxEnergy);
	}

	@Override public void onSetEnergy(BattleProperty property, int energy) {};

	@Override public void onSetStrategy(BattleProperty property, AbstractStrategy strategy) {};

	@Override public void onBuffAdd(BattleProperty property, BattleBuff buff) {
		int index = npc.getProperty().getBuffs().size()-1;
		BattleStatusBuff statusBuff = new BattleStatusBuff(index,buff);
		addInstance(statusBuff);
		world.createInstance(statusBuff);
	}

	@Override public void onBuffRemove(BattleProperty property, BattleBuff buff) {
		Collection<WorldStaticObject> instances = getInstances();
		BattleStatusBuff remove = null;
		
		// Find buff and update indexes
		for (WorldStaticObject instance : instances) {
			if (instance instanceof BattleStatusBuff) {
				BattleStatusBuff b = (BattleStatusBuff) instance;
				if (b.getType() == buff.getType())
					remove = b;
			}
		}
		
		// Remove the buff
		if (remove != null)
			remove.expire(buffRefreshTime/2);
		
		// Sets the buff refresh timer
		buffRefreshTimer = buffRefreshTime;
	}
	
	/*============================================================
	Private Methods
	============================================================*/
	
	/** Refreshes the index of all buffs. **/
	private void refreshBuffs() {
		int index = 0;
		for (WorldStaticObject instance : getInstances())
			if (instance instanceof BattleStatusBuff)
				((BattleStatusBuff) instance).setIndex(index++);
	}

}
